﻿package com.utils {
	import flash.display.Bitmap;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.TimerEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	import flash.utils.Timer;

	/**
	 * ...
	 * @author Liseen
	 */
	public class File extends EventDispatcher {
		public static const limit:int = 3;

		public static var onVersion:Function;
		private static var _temp:Dictionary = new Dictionary();
		private static var _id:int = 0;
		private static var _processes:Object = {};

		private var _uri:String;
		private var _loader:Loader;
		private var _applicationDomain:ApplicationDomain;
		private var _useNewDomain:Boolean = false;
		public var onProgress:Function;
		public var onComplete:Function;
		public var onError:Function;
		private var _lastBytes:uint = 0;
		private var _speed:Number = 0;
		private var _urlRnd:int = 0;
		private var _timer:Timer;
		private var _reloadCount:int = 3;

		public function File() {
			this._loader = new Loader();
			this.addTemp();
			this._reloadCount = File.limit;
		}

		public static function loadList(resUrlList:Array, callback:Function, progressHandler:Function = null, completeHandler:Function = null, errorHandler:Function = null):int {
			_id++;
			_processes[_id] = true;
			loadOne(resUrlList, 0, [], callback, progressHandler, completeHandler, errorHandler, _id);
			return _id;
		}

		public static function stopLoadList(_arg1:int):void {
			if (_arg1 && _processes[_arg1]) {
				_processes[_arg1] = false;
			}
		}

		private static function loadOne(resUrlList:Array, _arg2:int, _arg3:Array, callback:Function, progressHandler:Function = null, completeHandler:Function = null, errorHandler:Function = null, _arg8:int = 0):void {
			var len:int;
			var list:Array = resUrlList;
			var index:int = _arg2;
			var temp:Array = _arg3;
			var callback:Function = callback;
			var progress:Function = progressHandler;
			var oneCompleted:Function = completeHandler;
			var error:Function = errorHandler;
			var id:int = _arg8;
			var file:File = new (File)();
			temp.push(file);
			len = list.length;
			file.onComplete = function():void {
				if (false == _processes[id]) {
					delete _processes[id];
					return;
				}
				if ((index + 1) >= len) {
					delete _processes[id];
					callback(temp);
				} else {
					if ((oneCompleted is Function)) {
						oneCompleted(index);
					}
					loadOne(list, (index + 1), temp, callback, progress, oneCompleted, error, id);
				}
			}
			file.onProgress = function(_arg1:int, _arg2:int, _arg3:String):void {
				var _local4:int;
				if ((progress is Function)) {
					_local4 = Math.floor(_arg2 / _arg1 * 100);
					_local4 = Math.min(100, _local4);
					if (progress.length == 4) {
						progress(len, index, _local4, _arg3);
					} else {
						if (progress.length == 3) {
							progress(index, _local4, _arg3);
						} else {
							progress(index, _local4);
						}
					}
				}
			}
			file.onError = function():void {
				if (error is Function) {
					error(index);
				}
			}
			file.load(list[index]);
		}


		private function addEvent():void {
			var _local1:LoaderInfo = this._loader.contentLoaderInfo;
			_local1.addEventListener(Event.COMPLETE, this.complete);
			_local1.addEventListener(ProgressEvent.PROGRESS, this.progress);
			_local1.addEventListener(HTTPStatusEvent.HTTP_STATUS, this.httpStatus);
			_local1.addEventListener(IOErrorEvent.IO_ERROR, this.ioErrorHandler);
			_local1.addEventListener(SecurityErrorEvent.SECURITY_ERROR, this.securityErrorHandler);
		}

		private function removeEvent():void {
			var _local1:LoaderInfo = this._loader.contentLoaderInfo;
			_local1.removeEventListener(Event.COMPLETE, this.complete);
			_local1.removeEventListener(ProgressEvent.PROGRESS, this.progress);
			_local1.removeEventListener(HTTPStatusEvent.HTTP_STATUS, this.httpStatus);
			_local1.removeEventListener(IOErrorEvent.IO_ERROR, this.ioErrorHandler);
			_local1.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, this.securityErrorHandler);
		}

		public function load(resUrl:String):void {
			this._uri = resUrl;
			var params:String = "";
			if (onVersion is Function) {
				params = onVersion(resUrl);
				if (params != "") {
					params = ("?v=" + params);
				}
			}
			if (this._urlRnd) {
				params = (params + ((((params) ? "&" : "?") + "r=") + this._urlRnd));
			}
			//var _local3:URLRequest = new URLRequest(this._uri + _local2);
			var request:URLRequest = new URLRequest(this._uri);
			var context:LoaderContext = new LoaderContext();
			context.checkPolicyFile = true;
			context.applicationDomain = ((this._useNewDomain) ? new ApplicationDomain() : new ApplicationDomain(ApplicationDomain.currentDomain));
			this.addEvent();
			this._loader.load(request, context);
		}

		private function complete(_arg1:Event):void {
			this._applicationDomain = this._loader.contentLoaderInfo.applicationDomain;
			if (this.onComplete is Function) {
				this.onComplete();
			}
			this.removeEvent();
			this.removeTemp();
		}

		private function progress(_arg1:ProgressEvent):void {
			var _local2:int;
			var _local3:int;
			if (this.onProgress is Function) {
				if (this.onProgress.length == 3) {
					if ((_arg1.bytesLoaded - this._lastBytes) > 0) {
						this._speed = (_arg1.bytesLoaded - this._lastBytes);
						this._lastBytes = _arg1.bytesLoaded;
						_local2 = (this._speed / 0x0400);
						_local3 = (this._speed % 0x0400);
						this._speed = (_local2 + (Math.floor(_local3 / 0x0400 * 10) / 10));
					}
					this.onProgress(_arg1.bytesTotal, _arg1.bytesLoaded, (this._speed + "kb/s"));
				} else {
					this.onProgress(_arg1.bytesTotal, _arg1.bytesLoaded);
				}
			}
		}

		private function httpStatus(_arg1:HTTPStatusEvent):void {
		}

		private function securityErrorHandler(_arg1:SecurityErrorEvent):void {
			this.delayToLoad();
		}

		private function ioErrorHandler(_arg1:IOErrorEvent):void {
			this.delayToLoad();
		}


		private function addTemp():void {
			File._temp[this] = 1;
		}

		private function removeTemp():void {
			delete File._temp[this];
		}

		private function delayToLoad():void {
			this._loader.unload();
			if (this._reloadCount <= 0) {
				this.stopLoad();
				this.removeEvent();
				this.removeTemp();
				if (this.onError is Function) {
					this.onError();
				}
				return;
			}
			this._reloadCount--;
			this._timer = new Timer(100, 1);
			this._timer.addEventListener(TimerEvent.TIMER_COMPLETE, this.startLoad);
			this._timer.start();
		}

		private function startLoad(_arg1:TimerEvent):void {
			this.stopLoad();
			this._urlRnd++;
			if (this._urlRnd == 3) {
				this._urlRnd = Math.random() * 100;
			}
			this.load(this._uri);
		}

		private function stopLoad():void {
			this._timer.stop();
			this._timer.removeEventListener(TimerEvent.TIMER_COMPLETE, this.startLoad);
		}

		public function getClassByName(_arg1:String):Class {
			var className:String = _arg1;
			try {
				return (this._applicationDomain.getDefinition(className) as Class);
			} catch (e:Error) {
				throw(new Error(className + " not found in " + _uri + "\n") + e);
			}
			return null;

		}

		public function getClassObject(_arg1:String):Object {
			var _local2:Class = (this.getClassByName(_arg1) as Class);
			return new _local2();
		}

		public function get loader():Loader {
			return (this._loader);
		}

		public function get applicationDomain():ApplicationDomain {
			return (this._applicationDomain);
		}

		public function set useNewDomain(_arg1:Boolean):void {
			this._useNewDomain = _arg1;
		}

		public function get bytes():ByteArray {
			return (this._loader.contentLoaderInfo.bytes);
		}

		public function get bitmap():Bitmap {
			return this._loader.content as Bitmap;
		}

	}

}
